package com.electromagnetic.industry.software.manage.service.serviceimpl;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.text.StrFormatter;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.electromagnetic.industry.software.common.enums.*;
import com.electromagnetic.industry.software.common.exception.BizException;
import com.electromagnetic.industry.software.common.resp.ElectromagneticResult;
import com.electromagnetic.industry.software.common.util.EleCommonUtil;
import com.electromagnetic.industry.software.common.util.ElectromagneticResultUtil;
import com.electromagnetic.industry.software.common.util.UserThreadLocal;
import com.electromagnetic.industry.software.manage.mapper.EdFileInfoMapper;
import com.electromagnetic.industry.software.manage.pojo.models.EdFileInfo;
import com.electromagnetic.industry.software.manage.pojo.req.FolderResortDTO;
import com.electromagnetic.industry.software.manage.pojo.req.QueryPublishStatus;
import com.electromagnetic.industry.software.manage.pojo.resp.ProjectVO;
import com.electromagnetic.industry.software.manage.service.EdPrjService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

import static com.electromagnetic.industry.software.common.cons.ElectromagneticConstants.*;

@Slf4j
@Service
public class EdPrjServiceImpl extends ServiceImpl<EdFileInfoMapper, EdFileInfo> implements EdPrjService {

    @Resource
    private CommonService commonService;

    /**
     * 创建一个新的工程
     *
     * @param prjName 新的工程名
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ElectromagneticResult<?> createNewPrj(String prjName, int dataOwnCode) {

        if (!EleCommonUtil.isFileNameValid(prjName)) {
            String info = StrFormatter.format("{} {}，项目创建失败。", prjName, NAME_VALID_MSG);
            log.info(info);
            return ElectromagneticResultUtil.fail("-1", info);
        }

        // 首先检查工程是否存在
        LambdaQueryWrapper<EdFileInfo> queryWrapper = Wrappers.lambdaQuery(EdFileInfo.class)
                .eq(EdFileInfo::getParentId, PRJ_PARENT_ID)
                .eq(EdFileInfo::getDataOwn, dataOwnCode)
                .eq(EdFileInfo::getEffectFlag, EffectFlagEnum.EFFECT.code)
                .eq(EdFileInfo::getFileName, prjName);
        if (DataOwnEnum.isUserCode(dataOwnCode)) {
            queryWrapper.eq(EdFileInfo::getCreatedBy, UserThreadLocal.getUserId());
        }
        Long count = this.baseMapper.selectCount(queryWrapper);

        if (count > 0) {
            String info = StrFormatter.format("{} 项目已经存在", prjName);
            log.info(info);
            return ElectromagneticResultUtil.fail("-1", info);
        }

        try {
            // 保存信息到MySQL
            String maxPrjId = this.baseMapper.maxPrjId();
            Long prjCount;
            DataOwnEnum enumByCode = DataOwnEnum.getEnumByCode(dataOwnCode);
            LambdaQueryWrapper<EdFileInfo> qw = Wrappers.lambdaQuery(EdFileInfo.class).eq(EdFileInfo::getParentId, PRJ_PARENT_ID);
            switch (Objects.requireNonNull(enumByCode)) {
                case USER_PRJ, USER_FILE ->
                        prjCount = this.baseMapper.selectCount(qw.eq(EdFileInfo::getDataOwn, DataOwnEnum.USER_PRJ.code).eq(EdFileInfo::getCreatedBy, UserThreadLocal.getUserId()));
                case SYS_PRJ, SYS_FILE ->
                        prjCount = this.baseMapper.selectCount(qw.eq(EdFileInfo::getDataOwn, DataOwnEnum.SYS_PRJ.code));
                case REPO_PRJ, REPO_FILE ->
                        prjCount = this.baseMapper.selectCount(qw.eq(EdFileInfo::getDataOwn, DataOwnEnum.REPO_PRJ.code));
                default -> throw new BizException("参数错误");
            }
            int id = Integer.parseInt(StrUtil.isEmpty(maxPrjId) ? "100000" : maxPrjId);
            String newPrjId = String.valueOf(id + 1);

            EdFileInfo fileInfo = new EdFileInfo();
            fileInfo.newInit();
            String nowTimeStr = EleCommonUtil.getNowTimeStr();
            fileInfo.setId(newPrjId)
                    .setFileType("文件夹")
                    .setFileId(newPrjId)
                    .setFileName(prjName)
                    .setFileVersion(FILE_START_VERSION)
                    .setParentId(PRJ_PARENT_ID)
                    .setFileTime(nowTimeStr)
                    .setDataType(EleDataTypeEnum.FOLDER.code)
                    .setDataStatus(EleDataStatusEnum.NOT_PUBLISHED.code)
                    .setSaveStatus(EleDataSaveStatusEnum.SUCCESS.code)
                    .setFilePath(newPrjId)
                    .setSort(prjCount.intValue() + 1)
                    .setFileCode(commonService.createFileCode(newPrjId, EleDataTypeEnum.FOLDER.desc, FILE_START_VERSION, nowTimeStr))
                    .setDataOwn(dataOwnCode)
                    .setTemplateCode(IdUtil.fastSimpleUUID())
                    .setEffectFlag(EffectFlagEnum.EFFECT.code);
            this.baseMapper.insert(fileInfo);
            UserThreadLocal.setSuccessInfo("", newPrjId, "创建 {} 项目成功。", prjName);
        } catch (Exception e) {
            String info = StrFormatter.format("工程 {} 创建失败，具体为--->{}", prjName, e.getMessage());
            log.error(info, e);
            throw new BizException(info, e);
        }
        return ElectromagneticResultUtil.success(true);
    }

    /**
     * 修改项目名称
     *
     * @param prjId
     * @param newPrjName
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ElectromagneticResult<?> modifyPrjName(String prjId, String newPrjName, int dataOwnCode) {

        EdFileInfo fileInfo = this.baseMapper.selectById(prjId);
        String oldPrjName = fileInfo.getFileName();
        try {
            Assert.isTrue(EleCommonUtil.isFileNameValid(newPrjName), StrFormatter.format("{} {}，{} 修改失败。", newPrjName, NAME_VALID_MSG, oldPrjName));
            Long count = this.baseMapper.selectCount(Wrappers.lambdaQuery(EdFileInfo.class)
                    .eq(EdFileInfo::getParentId, PRJ_PARENT_ID)
                    .eq(EdFileInfo::getDataOwn, dataOwnCode)
                    .eq(EdFileInfo::getEffectFlag, EffectFlagEnum.EFFECT.code)
                    .eq(EdFileInfo::getFileName, newPrjName));
            if (count > 0) {
                String info = StrFormatter.format("{} 项目已经存在，{} 修改失败。", newPrjName, oldPrjName);
                log.info(info);
                return ElectromagneticResultUtil.fail("-1", info);
            }
            fileInfo.setFileName(newPrjName);
            this.baseMapper.updateById(fileInfo);
            UserThreadLocal.setSuccessInfo("", prjId, "修改工层名 {} 为 {} 成功。", oldPrjName, newPrjName);
        } catch (Exception e) {
            String info = StrFormatter.format("修改工程名异常--->{}，{}", newPrjName, e.getMessage());
            log.error(info, e);
            throw new BizException(info, e);
        }
        return ElectromagneticResultUtil.success(true);
    }

    /**
     * 删除一个项目，做逻辑删除
     *
     * @param prjId
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ElectromagneticResult<?> delete(String prjId, int dataOwnCode) {
        try {
            // 首先查看该工程下是否还有文件
            Long count = this.baseMapper.selectCount(Wrappers.lambdaQuery(EdFileInfo.class)
                    .eq(EdFileInfo::getDataType, EleDataTypeEnum.FILE.code)
                    .eq(EdFileInfo::getEffectFlag, EffectFlagEnum.EFFECT.code)
                    .likeRight(EdFileInfo::getFilePath, prjId + MYSQL_FILE_PATH_SPLIT));
            EdFileInfo prjFile = this.getById(prjId);
            Assert.isTrue(DataOwnEnum.isPrjCode(prjFile.getDataOwn()), "删除目录非工程");
            if (count > 0) {
                String info = StrFormatter.format("禁止废除非空项目，废除失败。");
                log.info(info);
                return ElectromagneticResultUtil.fail("-1", info);
            }

            LambdaQueryWrapper<EdFileInfo> queryWrapper = Wrappers.lambdaQuery(EdFileInfo.class)
                    .select(EdFileInfo::getId)
                    .likeRight(EdFileInfo::getFilePath, prjId + MYSQL_FILE_PATH_SPLIT);
            List<EdFileInfo> edFileInfos = this.baseMapper.selectList(queryWrapper);
            List<String> ids = edFileInfos.stream().map(EdFileInfo::getId).collect(Collectors.toList());
            ids.add(prjId);
            this.baseMapper.update(new EdFileInfo(), Wrappers.lambdaUpdate(EdFileInfo.class).set(EdFileInfo::getEffectFlag, EffectFlagEnum.NOT_EFFECTIVE.code).in(EdFileInfo::getId, ids));
            // 对原文件进行处理
            UserThreadLocal.setSuccessInfo("", prjId, "废除 {} 项目成功。", prjFile.getFileName());
            return ElectromagneticResultUtil.success(true);
        } catch (Exception e) {
            String info = "废除项目失败";
            log.error(info, e);
            throw new BizException(info, e);
        }
    }

    /**
     * 添加子集
     *
     * @param parentId
     * @param folderName
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ElectromagneticResult<?> addFolder(String parentId, String folderName, int dataOwnCode) {
        Assert.isTrue(EleCommonUtil.isFileNameValid(folderName), NAME_VALID_MSG);
        // 检查当前目录下有文件，如果有则不允许添加
        LambdaQueryWrapper<EdFileInfo> queryWrapper = Wrappers.lambdaQuery(EdFileInfo.class)
                .eq(EdFileInfo::getParentId, parentId)
                .eq(EdFileInfo::getEffectFlag, EffectFlagEnum.EFFECT.code);

        queryWrapper.and(qr -> qr.eq(EdFileInfo::getDataOwn, DataOwnEnum.USER_FILE.code)
                .or()
                .eq(EdFileInfo::getDataOwn, DataOwnEnum.REPO_FILE.code)
                .or()
                .eq(EdFileInfo::getDataOwn, DataOwnEnum.SYS_FILE.code));

        long count = this.baseMapper.selectCount(queryWrapper);

        if (count > 0) {
            return ElectromagneticResultUtil.fail("-1", StrFormatter.format("该层级目录下存在文件或者文件夹，不允许再定义层级目录。父目录id {}，子集名称 {}", parentId, folderName));
        }
        if (!commonService.notExistSameFolder(parentId, folderName, dataOwnCode)) {
            return ElectromagneticResultUtil.fail("-1", StrFormatter.format("子集名称 {} 已经存在，parent id {}", folderName, parentId));
        }
        int id = Integer.parseInt(this.baseMapper.maxPrjId());
        String folderId = String.valueOf(id + 1);
        ElectromagneticResult<?> electromagneticResult = commonService.addFolder(parentId, folderName, true, folderId, null, dataOwnCode);
        UserThreadLocal.setSuccessInfo(parentId, electromagneticResult.getData() + "", "添加子集 {} 成功", folderName);
        return electromagneticResult;
    }

    /**
     * 查询所有项目
     *
     * @return
     */
    @Override
    public ElectromagneticResult<?> queryAllPrjInfo(int querySource, String prjName) {

        /**
         * querySource=SYS_PRJ（管理员从层级定义处查询） querySource=USER_PRJ（用户从自定义层级结构处查询 querySource=REPO_PRJ
         */
        Map<Integer, List<String>> map;
        if (querySource == PrjQuerySource.SYS_PRJ.value) {
            map = commonService.querySysPrjTree(PrjQuerySource.SYS_PRJ.value, null, new ProjectVO(), prjName);
        } else if (querySource == PrjQuerySource.USER_PRJ.value) {
            map = commonService.queryUserPrjTree(PrjQuerySource.USER_PRJ.value, new ProjectVO(), prjName);
        } else {
            map = commonService.queryRepoPrjTree(PrjQuerySource.REPO_PRJ.value, null, new ProjectVO(), prjName);
        }
        List<String> res = map.getOrDefault(querySource, new ArrayList<>());
        List<ProjectVO> projectVOS = new ArrayList<>();
        res.forEach(e -> {
            ProjectVO projectVO = JSONUtil.toList(e, ProjectVO.class).get(0);
            projectVOS.add(projectVO);
        });
        projectVOS.sort(Comparator.comparing(ProjectVO::getSort));
        UserThreadLocal.setSuccessInfo("", "", "查询了所有工程");
        return ElectromagneticResultUtil.success(projectVOS);
    }

    /**
     * 子集拖拽重排序
     *
     * @param folderResortDTOList
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ElectromagneticResult<?> folderResort(List<FolderResortDTO> folderResortDTOList) {
        try {
            for (FolderResortDTO folderResortDTO : folderResortDTOList) {
                LambdaUpdateWrapper<EdFileInfo> updateWrapper = Wrappers.lambdaUpdate(EdFileInfo.class)
                        .set(EdFileInfo::getSort, folderResortDTO.getSort())
                        .eq(EdFileInfo::getId, folderResortDTO.getId());
                this.update(new EdFileInfo(), updateWrapper);
            }
            UserThreadLocal.setSuccessInfo("", "", "子集重排序成功");
            return ElectromagneticResultUtil.success(true);
        } catch (Exception e) {
            String info = "子集重排序异常";
            log.error(info, e);
            throw new BizException(info, e);
        }
    }

    /**
     * 项目发布
     *
     * @param prjId
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ElectromagneticResult<?> publish(String prjId, int dataOwnCode) {
        return commonService.publish(prjId, dataOwnCode);
    }

    /**
     * 删除子集
     *
     * @param fileId
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ElectromagneticResult<?> deleteFolder(String fileId, int dataOwnCode) {
        return commonService.deleteFolder(fileId);
    }

    /**
     * 层级沿用
     *
     * @param sourceId
     * @param targetId
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ElectromagneticResult<?> follow(String sourceId, String targetId, int dataOwnCode) {
        return commonService.follow(sourceId, targetId, dataOwnCode);
    }

    /**
     * 修改子集名称
     *
     * @param id
     * @param newFolderName
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ElectromagneticResult<?> modifyFolder(String id, String newFolderName, int dataOwnCode) {

        Assert.isTrue(EleCommonUtil.isFileNameValid(newFolderName), NAME_VALID_MSG);
        try {
            String parentId = this.baseMapper.selectById(id).getParentId();
            // 首先检查同层是否有同名目录
            Assert.isTrue(commonService.notExistSameFolder(parentId, newFolderName, dataOwnCode), StrFormatter.format("{} 子集名已经存在", newFolderName));
            this.baseMapper.update(new EdFileInfo(), Wrappers.lambdaUpdate(EdFileInfo.class)
                    .eq(EdFileInfo::getId, id)
                    .set(EdFileInfo::getFileName, newFolderName));
            UserThreadLocal.setSuccessInfo(parentId, id, "子集名称 {} 修改成功", newFolderName);
            return ElectromagneticResultUtil.success(true);
        } catch (Exception e) {
            String info = StrFormatter.format("修改子集名称为 {} 失败", newFolderName);
            log.error(info, e);
            throw new BizException(info);
        }
    }

    /**
     * 获取项目的发布状态
     *
     * @param queryPublishStatus
     * @return
     */
    @Override
    public ElectromagneticResult<?> publishStatus(QueryPublishStatus queryPublishStatus, int dataOwnCode) {
        Map<String, Integer> res = new HashMap<>();
        List<String> prjIds = queryPublishStatus.getPrjIds();
        List<EdFileInfo> edFileInfos = this.baseMapper.selectList(Wrappers.lambdaQuery(EdFileInfo.class).select(EdFileInfo::getFilePath)
                .eq(EdFileInfo::getEffectFlag, EffectFlagEnum.EFFECT.code)
                .eq(EdFileInfo::getDataOwn, dataOwnCode)
                .and(qr -> qr
                        .eq(EdFileInfo::getDataStatus, EleDataStatusEnum.NOT_PUBLISHED.code)
                        .or()
                        .eq(EdFileInfo::getDataStatus, EleDataStatusEnum.WAIT_DELETED.code)));
        Set<String> unpublishFiles = new HashSet<>();
        for (EdFileInfo edFileInfo : edFileInfos) {
            String filePath = edFileInfo.getFilePath();
            String prjId = filePath.split(MYSQL_FILE_PATH_SPLIT)[0];
            unpublishFiles.add(prjId);
        }
        for (String prjId : prjIds) {
            res.put(prjId, EleDataStatusEnum.PUBLISHED.code);
            if (unpublishFiles.contains(prjId)) {
                res.put(prjId, EleDataStatusEnum.NOT_PUBLISHED.code);
            }
        }
        UserThreadLocal.setSuccessInfo("", "", "获取用户层级发布状态成功");
        return ElectromagneticResultUtil.success(res);
    }

}
